/// File:		SinglyLinkedList.h
/// Author:		Dennis Norton
/// Date:		07/23/12
/// Purpose:	This component processes messages by system objects that tell the
///				application what to do.

#ifndef SINGLYLINKEDLIST_H_
#define SINGLYLINKEDLIST_H_

#include "../Utilities/Informant.h"

template<typename T>
class SinglyLinkedList
{
	template<typename T>
	struct Node
	{
		Node* Next;
		T Data;
	};

	Node<T>* _Head, *_Tail;
	size_t _ListSize;
public:
	SinglyLinkedList() : _Head(0), _Tail(0), _ListSize(0) {}
	~SinglyLinkedList(){ClearList();}

	/// Purpose:	Adds a new node to the end of the list.
	void AddToList(T Object)
	{
		Node<T>* ToAdd = new Node<T>();
		ToAdd->Data = Object;

		if(_Head)	// We have a head, so add to the end.
		{
			ToAdd->Next = 0;
			_Tail->Next = ToAdd;
			_Tail = ToAdd;

		}
		else	// This is the first item in the list
		{
			ToAdd->Next = 0;
			_Head = ToAdd;
			_Tail = _Head;
		}

		++_ListSize;
	}

	/// Purpose:	Removes the specified node from the list.
	void RemoveFromList(T Object)
	{
		Node<T>* CurrNode = _Head, *PrevNode = 0;

		while(CurrNode)
		{
			if(CurrNode->Data == Object)
			{
				// Link the nodes.. if we're not the head.
				if(PrevNode)
					PrevNode->Next = CurrNode->Next;
				else
					_Head = CurrNode->Next;

				// Delete from memory
				delete CurrNode;

				--_ListSize;

				// Break out of the loop
				break;
			}

			PrevNode = CurrNode;
			CurrNode = CurrNode->Next;
		}
	}

	/// Purpose:	Makes the entire list empty.
	void ClearList()
	{
		Node<T>* CurrNode = _Head;
		_Head = 0;
		while(CurrNode)
		{
			Node<T>* Deleting = CurrNode;
			CurrNode = CurrNode->Next;
			delete Deleting;
		}
		/*_Head = _Tail = 0;
		_ListSize = 0;*/
	}


	/// Purpose:	Returns the current size of the list.
	inline size_t Size() {return _ListSize;}

	/// Purpose:	Returns a reference to the head of the list.
	inline T& Front() {return _Head->Data;}

	/// Purpose:	Returns a reference to the last item in the list.
	T& Back() {return _Tail;}

	/// Purpose:	Indexs into the current list and returns a ref to the object.
	///				Very slow, O(N)
	T& operator[](int index)
	{
		try
		{
			if(index > _ListSize-1)
				throw "Array out of bounds. Index %d out of %d";

			int count = 0;

			Node<T>* CurrNode = _Head;
			while(count != index)
			{
				CurrNode = CurrNode->Next;
				++count;
			}

			return CurrNode->Data;
		}
		catch(char* err)
		{
			Informant::Log(LOCATION, err, index, _ListSize-1);
		}
	}
};

#endif